<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=147777
-->
<head>
  <title>Test for Bug 147777</title>
  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
  <script type="application/javascript" src="/tests/SimpleTest/WindowSnapshot.js"></script>
  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=147777">Mozilla Bug 147777</a>
<pre id="test">
<script type="application/javascript">

/** Test for Bug 147777 **/

// Because link-coloring for visited links is asynchronous, running
// reftests that involve link coloring requires that we poll for the
// correct result until all links are styled correctly.

// A requirement of these reftests is that the reference rendering is
// styled correctly when loaded.  We only poll for the tests.

var gTests = [
  // there's also an implicit "load visited-page.html" at the start,
  // thanks to the code below.

  // IMPORTANT NOTE: For these tests, the test and reference are not
  // snapshotted in the same way.  The REFERENCE (second file) is
  // assumed to be complete when loaded, but we poll for visited link
  // coloring on the TEST (first file) until the test passes.
  "== pseudo-classes-02.svg pseudo-classes-02-ref.svg",
  "!= color-on-link-1-ref.html color-on-visited-1-ref.html",
  "== color-on-link-1.html color-on-link-1-ref.html",
  "== color-on-link-before-1.html color-on-link-1-ref.html",
  "== color-on-visited-1.html color-on-visited-1-ref.html",
  "== color-on-visited-before-1.html color-on-visited-1-ref.html",
  "!= content-color-on-link-before-1-ref.html content-color-on-visited-before-1-ref.html",
  "== content-color-on-link-before-1.html content-color-on-link-before-1-ref.html",
  "== content-color-on-visited-before-1.html content-color-on-visited-before-1-ref.html",
  "== content-on-link-before-1.html content-before-1-ref.html",
  "== content-on-visited-before-1.html content-before-1-ref.html",
  "== color-on-text-decoration-1.html color-on-text-decoration-1-ref.html",
  "== color-on-bullets-1.html color-on-bullets-1-ref.html",
  // NOTE: background-color is tested by all the selector tests (and
  // also color-choice-1) and therefore doesn't have its own tests.
  // FIXME: Maybe add a test for selection colors (foreground and
  // background), if possible.
  "== width-on-link-1.html width-1-ref.html",
  "== width-on-visited-1.html width-1-ref.html",
  "== border-1.html border-1-ref.html",
  "== border-2a.html border-2-ref.html",
  "== border-2b.html border-2-ref.html",
  // FIXME: Commented out because of dynamic change handling bugs in
  // border-collapse tables that mean we get an incorrect rendering when
  // the asynchronous restyle-from-history arrives.
  //"== border-collapse-1.html border-collapse-1-ref.html",
  "== outline-1.html outline-1-ref.html",
  "== column-rule-1.html column-rule-1-ref.html",
  "!= column-rule-1.html column-rule-1-notref.html",
  "== color-choice-1.html color-choice-1-ref.html",
  "== selector-descendant-1.html selector-descendant-1-ref.html",
  "== selector-descendant-2.xhtml selector-descendant-2-ref.xhtml",
  "== selector-child-1.html selector-child-1-ref.html",
  "== selector-child-2.xhtml selector-child-2-ref.xhtml",
  "== selector-adj-sibling-1.html selector-adj-sibling-1-ref.html",
  "== selector-adj-sibling-2.html selector-adj-sibling-2-ref.html",
  "== selector-any-sibling-1.html selector-any-sibling-1-ref.html",
  "== selector-any-sibling-2.html selector-any-sibling-2-ref.html",
  "== subject-of-selector-descendant-1.html subject-of-selector-1-ref.html",
  "== subject-of-selector-descendant-2.xhtml subject-of-selector-descendant-2-ref.xhtml",
  "== subject-of-selector-child-1.html subject-of-selector-1-ref.html",
  "== subject-of-selector-adj-sibling-1.html subject-of-selector-1-ref.html",
  "== subject-of-selector-any-sibling-1.html subject-of-selector-1-ref.html",
  "== inherit-keyword-1.xhtml inherit-keyword-1-ref.html",
  "!= svg-image-visited-1-helper.svg lime100x100.svg",
  "!= svg-image-visited-2-helper.svg lime100x100.svg",
  // FIXME: commented out because dynamic changes on the non-first-line
  // part of the test don't work right when the link becomes visited.
  //"== first-line-1.html first-line-1-ref.html",
  "== white-to-transparent-1.html white-to-transparent-1-ref.html",
  "== link-root-1.xhtml link-root-1-ref.xhtml",
  "== mathml-links.html mathml-links-ref.html",
];

// Maintain a reference count of how many things we're waiting for until
// we can say the tests are done.
var gDelayCount = 0;
function AddFinishDependency()
  { ++gDelayCount; }
function RemoveFinishDependency()
  { if (--gDelayCount == 0) SimpleTest.finish(); }

// We record the maximum number of times we had to look at a test before
// it switched to the passing state (though we assume it's 10 to start
// rather than 0 so that we have a reasonable default).  Then we make a
// test "time out" if it takes more than gTimeoutFactor times that
// amount of time.  This allows us to report a test failure rather than
// making a test failure just show up as a timeout.
var gMaxPassingTries = 10;
var gTimeoutFactor = 10;

function loadVisitedPage()
{
  var element = document.createElement("iframe");
  element.addEventListener("load", visitedPageLoad, false);
  element.src = "css-visited/visited-page.html";
  document.body.appendChild(element);
  AddFinishDependency();
}

function visitedPageLoad()
{
  for (var i = 0; i < gTests.length; ++i) {
    startTest(i);
  }
  RemoveFinishDependency();
}

function takeSnapshot(iframe_element)
{
  return snapshotWindow(iframe_element.contentWindow, false);
}

function passes(op, shot1, shot2)
{
  var [correct, s1, s2] = compareSnapshots(shot1, shot2, op == "==");
  return correct;
}

function startTest(i)
{
  var testLine = gTests[i];
  var splitData = testLine.split(" ");
  var testData =
    { op: splitData[0], test: splitData[1], reference: splitData[2] };
  var tries = 0;

  // Maintain state specific to this test in the closure exposed to all
  // the functions nested inside this one.

  function startIframe(url)
  {
    var element = document.createElement("iframe");
    element.addEventListener("load", handleLoad, false);
    // smaller than normal reftests, but enough for these
    element.setAttribute("style", "width: 30em; height: 10em");
    element.src = "css-visited/" + url;
    document.body.appendChild(element);
    function handleLoad(event)
    {
      iframe.loaded = true;
      if (iframe == reference) {
        reference.snapshot = takeSnapshot(element);
      }
      var other = (iframe == test) ? reference : test;
      if (other.loaded) {
        // Always wait at least 100ms, so that any test that switches
        // from passing to failing when the asynchronous link coloring
        // happens should fail at least some of the time.
        setTimeout(checkTest, 100);
      }
    }
    function checkTest()
    {
      var test_snapshot = takeSnapshot(test.element);
      if (passes(testData.op, test_snapshot, reference.snapshot)) {
        if (tries > gMaxPassingTries) {
          gMaxPassingTries = tries;
        }
        report(true);
      } else {
        ++tries;
        if (tries > gMaxPassingTries * gTimeoutFactor) {
          info("Giving up after " + tries + " tries, " +
               "maxp=" + gMaxPassingTries +
               "fact=" + gTimeoutFactor);
          report(false);
        } else {
          // Links might not have been colored yet.  Try again in 100ms.
          setTimeout(checkTest, 100);
        }
      }
    }
    function report(result)
    {
      ok(result, "(" + i + ") " +
                 testData.op + " " + testData.test + " " + testData.reference);
      RemoveFinishDependency();
    }
    var iframe = { element: element, loaded: false };

    return iframe;
  }

  AddFinishDependency();
  var test = startIframe(testData.test);
  var reference = startIframe(testData.reference);
}

SimpleTest.waitForExplicitFinish();
SimpleTest.requestFlakyTimeout("untriaged");
loadVisitedPage();

</script>
</pre>
</body>
</html>
